www.gusucode.com > VC++ 三维图形生成和察看工具 > VC++ 三维图形生成和察看工具/code/mesh/Lib3D/Face3d.cpp

    //Download by http://www.NewXing.com
//********************************************
// Face3d.cpp
//********************************************
// class CFace3d
//********************************************
// alliez@usc.edu
// Created : 10/12/97
// Modified : 09/02/98
//********************************************

#include "stdafx.h"

#include "Base3d.h"
#include "Face3d.h"

//////////////////////////////////////////////
// CONSTRUCTORS
//////////////////////////////////////////////

//********************************************
// Constructor
//********************************************
CFace3d::CFace3d()
{
	for(int i=0;i<3;i++)
	  m_pFace[i] = NULL;
	for(i=0;i<6;i++)
	  m_pVertex[i] = NULL;
	m_Flag = 0;
}

//********************************************
// Constructor
//********************************************
CFace3d::CFace3d(CVertex3d *pVertex1,
								 CVertex3d *pVertex2,
								 CVertex3d *pVertex3)
{
	// Face
	for(int i=0;i<3;i++)
	  m_pFace[i] = NULL;
	// Vertices
	Set(pVertex1,pVertex2,pVertex3);
	for(i=3;i<6;i++)
	  m_pVertex[i] = NULL;

	// Normal
	m_Normal.Set(0.0f,0.0f,0.0f);

	m_Flag = 0;
}


//********************************************
// Constructor
//********************************************
CFace3d::CFace3d(CFace3d *pFace)
{
	Set(pFace);
	m_Flag = 0;
}


//////////////////////////////////////////////
// DATAS
//////////////////////////////////////////////

//********************************************
// Set
//********************************************
inline void CFace3d::Clear()
{
	for(int i=0;i<3;i++)
	  m_pFace[i] = NULL;
	for(i=0;i<6;i++)
	  m_pVertex[i] = NULL;
	m_Flag = 0;
}

//********************************************
// Equal
//********************************************
int CFace3d::Equal(CFace3d *pFace)
{
	return (HasVertex(pFace->v1()) && 
		      HasVertex(pFace->v2()) &&
					HasVertex(pFace->v3()));
}

//********************************************
// IsValid
//********************************************
int CFace3d::IsValid()
{
	int success = 1;

	success &= (m_pFace[0] != this);
	success &= (m_pFace[1] != this);
	success &= (m_pFace[2] != this);

	// Different neighbors, if there are
	success &= ((m_pFace[0] != m_pFace[1]) || (m_pFace[0] == NULL));
	success &= ((m_pFace[0] != m_pFace[2]) || (m_pFace[0] == NULL));
	success &= ((m_pFace[1] != m_pFace[2]) || (m_pFace[1] == NULL));

#ifdef _DEBUG
	if(!success)
		{
		TRACE("Face [%x] has the same neighbors\n",this);
		}
#endif

	// Different vertices
	success &= (m_pVertex[0] != m_pVertex[1]);
	success &= (m_pVertex[1] != m_pVertex[2]);
	success &= (m_pVertex[0] != m_pVertex[2]);

/*
#ifdef _DEBUG
	if(NbFaceNeighbor() != 3)
		{
		TRACE("Face [%x] has %d neighbors\n",NbFaceNeighbor());
		}
#endif
*/

#ifdef _DEBUG
	if(!success)
		{
		TRACE("Face [%x] has the same vertices \n",this);
		}
#endif

	// Reciproc. neighboring
	for(int i=0;i<3;i++)
	{
		CFace3d *pFace = f(i);
		if(pFace != NULL)
		{
			if(!pFace->HasNeighbor(this))
			{
			TRACE("Face [%x] has invalid reciproc. neighboring \n",this);
			success = 0;
			}
		}
	}

	return success;
}

//********************************************
// Set
//********************************************
inline void CFace3d::Set(CVertex3d *pVertex1,
												 CVertex3d *pVertex2,
												 CVertex3d *pVertex3)
{
	m_pVertex[0] = pVertex1;
	m_pVertex[1] = pVertex2;
	m_pVertex[2] = pVertex3;
}

//********************************************
// Set
//********************************************
inline void CFace3d::Set(CFace3d *pFace1,
												 CFace3d *pFace2,
												 CFace3d *pFace3)
{
	m_pFace[0] = pFace1;
	m_pFace[1] = pFace2;
	m_pFace[2] = pFace3;
}

//********************************************
// Set
//********************************************
inline void CFace3d::Set(CVertex3d *pVertex1,
												 CVertex3d *pVertex2,
												 CVertex3d *pVertex3,
												 CFace3d *pFace1,
												 CFace3d *pFace2,
												 CFace3d *pFace3)
{
	m_pVertex[0] = pVertex1;
	m_pVertex[1] = pVertex2;
	m_pVertex[2] = pVertex3;
	m_pFace[0] = pFace1;
	m_pFace[1] = pFace2;
	m_pFace[2] = pFace3;
}

//********************************************
// Set
//********************************************
inline void CFace3d::Set(CFace3d *pFace)
{
	Set(pFace->v1(),pFace->v2(),pFace->v3());
	Set(pFace->f1(),pFace->f2(),pFace->f3());
}

//********************************************
// SetFlagOnVerticesIfDiff
//********************************************
void CFace3d::SetFlagOnVerticesIfDiff(int FlagDiff,
																			int flag)
{
	for(int i=0;i<3;i++)
	{
		CVertex3d *pVertex = v(i);
		if(pVertex->GetFlag() != FlagDiff)
			pVertex->SetFlag((char)flag);
	}
}


//********************************************
// IndexFrom
//********************************************
int CFace3d::IndexFrom(CVertex3d *pVertex)
{
	ASSERT(HasVertex(pVertex));
	for(int i=0;i<3;i++)
		if(m_pVertex[i]==pVertex)
			return i;
	return 0;
}


//********************************************
// GetCenter
// Allocate on the heap
//********************************************
CVertex3d* CFace3d::GetCenter(void)
{
	CVertex3d* pVertex = new CVertex3d;
	pVertex->x((m_pVertex[0]->x()+m_pVertex[1]->x()+m_pVertex[2]->x())/3.0f);
	pVertex->y((m_pVertex[0]->y()+m_pVertex[1]->y()+m_pVertex[2]->y())/3.0f);
	pVertex->z((m_pVertex[0]->z()+m_pVertex[1]->z()+m_pVertex[2]->z())/3.0f);
	return pVertex;
}

//********************************************
// FindNearestVertex
//********************************************
CVertex3d *CFace3d::FindNearestVertex(CVertex3d *pVertex)
{
	CVertex3d *pV = v(0);
	double MinDistance = DistanceSquare(pVertex,v(0));
	for(int i=1;i<3;i++)
	{
		double tmp = DistanceSquare(pVertex,v(i));
		if(tmp < MinDistance)
		{
			MinDistance = tmp;
			pV = v(i);
		}
	}
	return pV;
}


//********************************************
// ColorSharpEdge
//********************************************
void CFace3d::ColorSharpEdge(double threshold,
														 CColor &color)
{
	for(int i=0;i<3;i++)
		if(SinAngle(this,f(i)) >= threshold)
		{
			v(i)->SetColor(color);
			v((i+1)%3)->SetColor(color);
		}
}

//********************************************
// ColorSharpEdge
//********************************************
int CFace3d::GetSharpEdge(double threshold,
													int *SharpEdge)
{
	int success = 0;
	for(int i=0;i<3;i++)
		if(f(i) != NULL)
			if(SinAngle(this,f(i)) >= threshold)
			{
				SharpEdge[i]=1;			
				success = 1;
			}
	return success;
}

//********************************************
// HasSharpEdge
//********************************************
int CFace3d::HasSharpEdge(double threshold)
{
	for(int i=0;i<3;i++)
	{
		double sinus = SinAngle(this,f(i));
		//TRACE("SinAngle : %g\n",sinus);
		if(sinus >= threshold)
			return 1;
	}
	return 0;
}


//////////////////////////////////////////////
// DATA ACCESS
//////////////////////////////////////////////

//********************************************
// GetType
//********************************************
int CFace3d::GetType()
{
	return TYPE_FACE3D;
}

//********************************************
// NbVertex
//********************************************
int CFace3d::NbVertex()
{
	int NbVertex = 0;
	for(int i=0;i<6;i++)
	  NbVertex += (m_pVertex[i] != NULL);
	return NbVertex;
}

//********************************************
// NbFaceNeighbor
//********************************************
int CFace3d::NbFaceNeighbor()
{
	int NbFace = 0;
	NbFace += (m_pFace[0] != NULL);
	NbFace += (m_pFace[1] != NULL);
	NbFace += (m_pFace[2] != NULL);
	return NbFace;
}


//////////////////////////////////////////////
// PROCESSING
//////////////////////////////////////////////


//********************************************
// CalculateNormal
//********************************************
void CFace3d::CalculateNormal()
{
	CVector3d u(m_pVertex[0],m_pVertex[1]);
	CVector3d v(m_pVertex[0],m_pVertex[2]);
	u.Inner(v);
	m_Normal.Set(u);
	m_Normal.NormalizeL2();
}





//////////////////////////////////////////////
// MISC
//////////////////////////////////////////////

//********************************************
// HasVertex
//********************************************
int CFace3d::HasVertex(CVertex3d *pVertex)
{
	return (m_pVertex[0] == pVertex ||
		      m_pVertex[1] == pVertex ||
		      m_pVertex[2] == pVertex);
}

//********************************************
// HasVertexWithFlag
//********************************************
int CFace3d::HasVertexWithFlag(int flag)
{
	return (m_pVertex[0]->GetFlag() == flag ||
		      m_pVertex[1]->GetFlag() == flag ||
		      m_pVertex[2]->GetFlag() == flag);
}

//********************************************
// HasVertex
//********************************************
int CFace3d::HasVertex(CVertex3d *pVertex,
											 int *index)
{
	for(int i=0;i<3;i++)
		if(m_pVertex[i] == pVertex)
			{
			*index = i;
			return 1;
			}
	return 0;
}

//********************************************
// HasVertex
//********************************************
int CFace3d::HasNeighbor(CFace3d *pFace)
{
	return (m_pFace[0] == pFace ||
		      m_pFace[1] == pFace ||
		      m_pFace[2] == pFace);
}


//********************************************
// HasVertex
//********************************************
int CFace3d::HasNeighbor(CFace3d *pFace,
												 int *index)
{
	for(int i=0;i<3;i++)
		if(m_pFace[i] == pFace)
			{
			*index = i;
			return 1;
			}
	return 0;
}


//********************************************
// GetNeighborExclusive
// Get neighboring face wich has pVertexHas
// and has not pVertexHasNot
//********************************************
CFace3d *CFace3d::GetNeighborExclusive(CVertex3d *pVertexHas,
																			 CVertex3d *pVertexHasNot)
{
	for(int i=0;i<3;i++)
	{
		CFace3d *pFace = f(i);
		if(pFace != NULL)
				if(pFace->HasVertex(pVertexHas) && 
					!pFace->HasVertex(pVertexHasNot))
					return pFace;
	}	
	return NULL;
}

//********************************************
// GetVertexExclusive
//********************************************
CVertex3d *CFace3d::GetVertexExclusive(CVertex3d *pV0,
																			 CVertex3d *pV1)
{
	for(int i=0;i<3;i++)
		if(v(i) != pV0 && v(i) != pV1)
			return v(i);
	return NULL;
}


//********************************************
// GetVertexExclusive
// Return vertex common to this and pFace,
// but pV
//********************************************
CVertex3d *CFace3d::GetVertexExclusive(CVertex3d *pV,
																			 CFace3d *pFace)
{
	for(int i=0;i<3;i++)
		if(v(i) != pV && pFace->HasVertex(v(i)))
			return v(i);
	return NULL;
}


//********************************************
// GetFaceNeighborExclusive
//********************************************
CFace3d *CFace3d::GetFaceNeighborExclusive(CFace3d *pF0,
																					 CFace3d *pF1)
{
	for(int i=0;i<3;i++)
		if(f(i) != pF0 && f(i) != pF1)
			return f(i);
	return NULL;
}


//********************************************
// GetVertexFaceNeighborExclusive
// Get vertex on neighboring face, which is not 
// on "this".
// index : neighboring face
//********************************************
CVertex3d *CFace3d::GetVertexFaceNeighborExclusive(unsigned int index)
{
	CFace3d *pFace = m_pFace[index%3];
	for(int i=0;i<3;i++)
		if(!this->HasVertex(pFace->v(i)))
			return pFace->v(i);
	return NULL;
}


//********************************************
// JointNeighbor
//********************************************
int CFace3d::JointNeighbor(CFace3d **pFace0,
													 CFace3d **pFace1)
{
	ASSERT(NbFaceNeighbor()==2);

	if(NbFaceNeighbor()!=2)
		return 0;

	// Find 2 neighbors
	CFace3d *pFaceNeighbor[2];
	int k=0;
	for(int i=0;i<3;i++)
	{
		if(m_pFace[i] != NULL)
			pFaceNeighbor[k++] = m_pFace[i];
	}
	ASSERT(k==2);
	if(k!=2)
		return 0;

	ASSERT(pFaceNeighbor[0]->HasNeighbor(this));
	ASSERT(pFaceNeighbor[1]->HasNeighbor(this));
	ASSERT(pFaceNeighbor[0] != this);
	ASSERT(pFaceNeighbor[1] != this);

	*pFace0 = pFaceNeighbor[0];
	*pFace1 = pFaceNeighbor[1];

	pFaceNeighbor[0]->UpdateNeighbor(this,pFaceNeighbor[1]);
	pFaceNeighbor[1]->UpdateNeighbor(this,pFaceNeighbor[0]);
	
	return 1;
}



//********************************************
// UpdateVertex
//********************************************
int CFace3d::UpdateVertex(CVertex3d *pOld,
													CVertex3d *pNew)
{
	int index;
	if(HasVertex(pOld,&index))
		{
		v(index,pNew);
		CalculateNormal(); // Update normal
		return 1;
		}
	return 0;
}

//********************************************
// UpdateNeighbor
//********************************************
int CFace3d::UpdateNeighbor(CFace3d *pOld,
													  CFace3d *pNew)
{
	int index;
	if(HasNeighbor(pOld,&index))
	{
		f(index,pNew);
		return 1;
	}
	return 0;
}

//********************************************
// Share2Vertex (exactly)
//********************************************
int CFace3d::Share2Vertex(CFace3d *pFace)
{
	if(pFace == NULL)
		return 0;
	int NbSharedVertex = 0;
	for(int i=0;i<3;i++)
		for(int j=0;j<3;j++)
			NbSharedVertex += (pFace->v(i) == m_pVertex[j]);
	return (NbSharedVertex == 2);
}

//********************************************
// Share2Vertex (exactly)
// Get sharing edge index info
//********************************************
int CFace3d::Share2Vertex(CFace3d *pFace,
													 int *IndexEdgeThis,
													 int *IndexEdgeOther)
{
	if(!Share2Vertex(pFace))
		return 0;

	int IndexThis[3] = {0,0,0};
	int IndexOther[3] = {0,0,0};

	for(int i=0;i<3;i++)
		for(int j=0;j<3;j++)
			if(pFace->v(i) == m_pVertex[j]) 
			{ 
				IndexThis[j] = 1;
				IndexOther[i] = 1; 
			}

	// Set IndexEdges
	*IndexEdgeThis = (IndexThis[0] && IndexThis[1]) ? 0 : (IndexThis[1] && IndexThis[2]) ? 1 : 2;
	*IndexEdgeOther = (IndexOther[0] && IndexOther[1]) ? 0 : (IndexOther[1] && IndexOther[2]) ? 1 : 2;

	// ** DEBUG **
	if(*IndexEdgeThis == 2)
		{
		ASSERT(IndexThis[0] && IndexThis[2]);
		}
	if(*IndexEdgeOther == 2)
		{
		ASSERT(IndexOther[0] && IndexOther[2]);
		}

	return 1;
}

//********************************************
// Share2Vertex (exactly)
// Get sharing edge index info
//********************************************
int CFace3d::Share2Vertex(CFace3d *pFace,
													 CVertex3d **pSharedV1,
													 CVertex3d **pSharedV2)
{
	int EdgeThis;
	int EdgeOther;
	if(!Share2Vertex(pFace))
		{
		*pSharedV1 = NULL;
		*pSharedV2 = NULL;
		return 0;
		}
	Share2Vertex(pFace,&EdgeThis,&EdgeOther);
	*pSharedV1 = v(EdgeThis);
	*pSharedV2 = v((EdgeThis+1)%3);
	return 1;
}

//********************************************
// Share1Vertex (exactly)
//********************************************
int CFace3d::Share1Vertex(CFace3d *pFace)
{
	int NbSharedVertex = 0;
	for(int i=0;i<3;i++)
		for(int j=0;j<3;j++)
			NbSharedVertex += (pFace->v(i) == m_pVertex[j]);
	return (NbSharedVertex == 1);
}


//********************************************
// UpdateVertexRecursive
//********************************************
int CFace3d::UpdateVertexRecursive(CVertex3d *pVertexOld,
																	 CVertex3d *pVertexNew)
{
	if(pVertexOld == pVertexNew)
		return 0;
	//TRACE("Update vertex %x in face %x\n",pVertexOld,this);
	this->UpdateVertex(pVertexOld,pVertexNew);
	for(int i=0;i<3;i++)
	{
		CFace3d *pFace = f(i);
		if(pFace != NULL)
			if(pFace->HasVertex(pVertexOld))
				pFace->UpdateVertexRecursive(pVertexOld,pVertexNew);
	}
	return 1;
}



//////////////////////////////////////////////
// DEBUG
//////////////////////////////////////////////

//********************************************
// Trace
//********************************************
void CFace3d::Trace()
{
	TRACE("\n");
	TRACE("Face %x\n",this);
	TRACE("Vertex   : %d\n",NbVertex());
	TRACE("Face (n) : %d\n",NbFaceNeighbor());
	TRACE("Normal   : %s\n",(m_Normal.GetNormL2Square()==0) ? "no" : "yes");
	TRACE("Vertices : (%g,%g,%g) (%g,%g,%g) (%g,%g,%g) \n",
		m_pVertex[0]->x(),m_pVertex[0]->y(),m_pVertex[0]->z(),
		m_pVertex[1]->x(),m_pVertex[1]->y(),m_pVertex[1]->z(),
		m_pVertex[2]->x(),m_pVertex[2]->y(),m_pVertex[2]->z());
	TRACE("Normal   : (%g,%g,%g)\n",m_Normal.x(),m_Normal.y(),m_Normal.z());

	// ** DEBUG **
	/*
	for(int i=0;i<3;i++)
		m_pVertex[i]->Trace();
		*/
}


//////////////////////////////////////////////
// OPENGL
//////////////////////////////////////////////

//********************************************
// glDraw
// Highlights face and its neighbors
//********************************************
void CFace3d::glDraw(unsigned char *ColorFace,
										 CMesh3d *pMesh /* = NULL */,
										 unsigned char *ColorNeightbor /* = NULL */)
{
	// Transform
	if(pMesh != NULL)
		{
			CTransform *pTransform = pMesh->GetTransform();
		::glPushMatrix();

			// Position / translation / scaling
			glTranslatef(pTransform->GetTranslation()->x(),
									 pTransform->GetTranslation()->y(),
									 pTransform->GetTranslation()->z());

			glScalef(pTransform->GetScale()->x(),
							 pTransform->GetScale()->y(),
							 pTransform->GetScale()->z());

			glRotatef(pTransform->GetValueRotation(),
								pTransform->GetRotation()->x(),
								pTransform->GetRotation()->y(),
								pTransform->GetRotation()->z());
		}

	// Neighbor
	if(ColorNeightbor != NULL)
	{
		glColor3ub(ColorNeightbor[0],ColorNeightbor[1],ColorNeightbor[2]);
		for(int k=0;k<3;k++)
		{
			CFace3d *pFace = f(k);
			if(pFace != NULL)
				{
				::glBegin(GL_POLYGON);
					::glVertex3f(pFace->v1()->x(),pFace->v1()->y(),pFace->v1()->z());
					::glVertex3f(pFace->v2()->x(),pFace->v2()->y(),pFace->v2()->z());
					::glVertex3f(pFace->v3()->x(),pFace->v3()->y(),pFace->v3()->z());
				::glEnd();
				}
		}
	}

	// Main face
	glColor3ub(ColorFace[0],ColorFace[1],ColorFace[2]);

	::glBegin(GL_POLYGON);
		for(int i=0;i<3;i++)
			::glVertex3f(m_pVertex[i]->x(),m_pVertex[i]->y(),m_pVertex[i]->z());
	::glEnd();

	if(pMesh != NULL)
	{
		::glPopMatrix();
	}
}


//********************************************
// Area
//********************************************
double CFace3d::Area()
{
	return ::Area(m_pVertex[0],m_pVertex[1],m_pVertex[2]);
}

//********************************************
// Perimeter
//********************************************
double CFace3d::Perimeter()
{
	return (::Distance(m_pVertex[0],m_pVertex[1]) + 
		      ::Distance(m_pVertex[1],m_pVertex[2]) +
					::Distance(m_pVertex[2],m_pVertex[0]));
}

//********************************************
// Compacity
//********************************************
double CFace3d::Compacity()
{
	double perimeter = Perimeter();
	if(perimeter == 0.0f)
	{
		TRACE("CFace3d::Compacity : null triangle\n");
		return 0.0;
	}
	return (4.0*PI*Area()/(perimeter*perimeter));
}


// ** EOF **